package planner

import (
	"mini-sql/model"
	"mini-sql/planner/plan"
	"mini-sql/storage"
)

func CreatePlan(statement *model.QueryStatement, storePool *storage.StorePool) plan.PlanNode {
	if statement.InsertStatement != nil {
		return plan.NewInsertPlanNode(statement.InsertStatement, storePool)
	}
	if statement.SelectStatement != nil {
		return NewSelectPlan(statement.SelectStatement, storePool)
	}
	if statement.UpdateStatement != nil {
		return NewUpdatePlan(statement.UpdateStatement, storePool)
	}
	if statement.DeleteStatement != nil {
		return NewDeletePlan(statement.DeleteStatement, storePool)
	}
	return nil
}

func NewDeletePlan(deleteStatement *model.DeleteStatement, storePool *storage.StorePool) plan.PlanNode {
	selectStatement := &model.SelectStatement{
		ColumnNames: []*model.Expr{
			{
				ExprType: model.ExprTypeStar,
				StrValue: "*",
			},
		},
		FromClause:  deleteStatement.TableRef,
		WhereClause: deleteStatement.WhereClause,
	}
	root := plan.NewScanPlanNode(selectStatement, storePool)
	root = plan.NewWherePlanNode(root, selectStatement)
	root = plan.NewSelectPlanNode(root, selectStatement)
	root = plan.NewDeletePlanNode(root, deleteStatement, storePool)
	return root
}

func NewUpdatePlan(updateStatement *model.UpdateStatement, storePool *storage.StorePool) plan.PlanNode {
	selectStatement := &model.SelectStatement{
		ColumnNames: []*model.Expr{
			{
				ExprType: model.ExprTypeStar,
				StrValue: "*",
			},
		},
		FromClause:  updateStatement.TableRef,
		WhereClause: updateStatement.WhereClause,
	}
	root := plan.NewScanPlanNode(selectStatement, storePool)
	root = plan.NewWherePlanNode(root, selectStatement)
	root = plan.NewSelectPlanNode(root, selectStatement)
	root = plan.NewUpdatePlanNode(root, updateStatement, storePool)
	return root
}

func NewSelectPlan(selectStatement *model.SelectStatement, storePool *storage.StorePool) plan.PlanNode {
	root := plan.NewScanPlanNode(selectStatement, storePool)
	root = plan.NewWherePlanNode(root, selectStatement)
	root = plan.NewSelectPlanNode(root, selectStatement)
	return root
}
